home *** CD-ROM | disk | FTP | other *** search
/ C/C++ Users Group Library 1997 August / Walnut Creek CDROM.7z / VOL_400 / 466_01 / SRC / MAIN.CPP < prev    next >
Encoding:
C/C++ Source or Header  |  1996-12-20  |  11.9 KB  |  537 lines

  1. #include <afx.h>
  2. #include <afxtempl.h>
  3. #include <process.h>        // for _getpid()
  4. #include <io.h>                // for findfirst()
  5. #include "parse.h"
  6. #include "topiclog.h"
  7. #include "fmtspec.h"
  8. #include "docexpr.h"
  9. #include "errmsg.h"
  10. #include "cmdargs.h"
  11. #include "extract.h"
  12. #include "output.h"
  13. #include "adoutput.h"
  14.  
  15. #ifdef _DEBUG
  16. #define new DEBUG_NEW
  17. #endif
  18.  
  19. // Global variables
  20.  
  21. RUNOPTIONS run;
  22. FormatInfo fmt;
  23. CTopicLog  log;
  24.  
  25. void GenerateTempFilename(CString &sName);
  26. int GenerateOutputFilename(CString &sOutput, const char *szInput1, const char *szExt);
  27. void GenerateOutput(CTopicLog &log, RUNOPTIONS &run, FormatInfo &fmt, CFile &fileTemp, CAdOutput &fileOutput);
  28. int SeekTail(CFile &fileOutput, FormatInfo &fmt);
  29. int PopulateLog(CTopicLog &log, const char *szFilename);
  30. void PrintVersion(const char *);
  31.  
  32. int main(int argc, char **argv)
  33. {
  34. TRY
  35. {
  36.     int nRet = 0;
  37.     int n, i;
  38.     const char *sz;
  39.     
  40.     CAdOutput fileOutput;
  41.     CFile fileTemp;
  42.     CFileException e;
  43.  
  44.     CString sAutoduckName;
  45.     CString sAutoduckFmtName;
  46.  
  47.     sAutoduckName.LoadString(IDS_APPNAME);
  48.     sAutoduckFmtName.LoadString(IDS_APPFMTNAME);
  49.  
  50.     // Announce version info
  51.  
  52.     PrintVersion(sAutoduckName);
  53.  
  54.     // If no arguments, print help
  55.     if(argc == 1)
  56.     {
  57.         Usage(sAutoduckName, sAutoduckFmtName);
  58.         return 0;
  59.     }
  60.     
  61.     // Parse the command line
  62.  
  63.     nRet = SetRtOptions(run, fmt, argv, argc, sAutoduckFmtName);
  64.     if(nRet)
  65.         return nRet;
  66.  
  67.     // Open format files.
  68.  
  69.     for(i = 0, n = run.asFmtFiles.GetSize(); i < n; i++)
  70.     {
  71.         sz = *run.asFmtFiles[i];
  72.  
  73.         nRet = GetFormatFile(sz, argv[0], run.sOutputType, fmt, run.nOptions.Verbose);
  74.         if(nRet)
  75.         {
  76.             PrintError(sz, fmt.lErrLine, nRet);
  77.             goto ExitError;
  78.         }
  79.     }
  80.  
  81.     // Make sure all's right with the format tags.
  82.  
  83.     if(!ValidateFormats(fmt))
  84.         return 1;
  85.  
  86.     // Open the log file, if specified.
  87.  
  88.     nRet = PopulateLog(log, run.sLogFileIn);
  89.     if(nRet)
  90.     {
  91.         PrintError(run.sLogFileIn, NO_LINE, nRet);
  92.         goto ExitError;
  93.     }
  94.  
  95.     // Open the temp output file - stores the extracted comment text.
  96.  
  97.     GenerateTempFilename(run.sTempFile);
  98.     if(!fileTemp.Open(run.sTempFile, CFile::modeCreate | 
  99.                         CFile::modeReadWrite | CFile::typeBinary, &e))
  100.     {
  101.         PrintError(run.sTempFile, NO_LINE, e.m_cause + 100);
  102.         nRet = e.m_cause;
  103.         goto ExitError;
  104.     }
  105.  
  106.     // Open the final output file - do it now to make sure it isn't
  107.     // already open or something.
  108.     
  109.     if(!run.nOptions.NoOutput)
  110.     {
  111.         // Open the output file, first generating a default name if
  112.         // none provided
  113.  
  114.         if(run.sOutputFile.IsEmpty())
  115.         {
  116.             CFmtToken *pfmt = (CFmtToken *)fmt.token.Get(NULL);
  117.             
  118.             ASSERT(pfmt);
  119.             ASSERT(run.asInputFiles.GetSize() > 0);
  120.  
  121.             nRet = GenerateOutputFilename(run.sOutputFile, *run.asInputFiles[0], pfmt->GetExtension());
  122.             if(nRet)
  123.             {
  124.                 PrintError(NULL, NO_LINE, nRet);
  125.                 goto ExitError;
  126.             }
  127.  
  128.             fprintf(stdout, "Output file is %s.\n", (const char *)run.sOutputFile);
  129.         }
  130.  
  131.         int nOptions;
  132.         CFileStatus status;
  133.         if(run.nOptions.Concat && CFile::GetStatus(run.sOutputFile, status))
  134.         {
  135.             nOptions = CFile::modeReadWrite | CFile::typeBinary;
  136.         }
  137.         else
  138.         {
  139.             nOptions = CFile::modeWrite | CFile::modeCreate | CFile::typeBinary;
  140.             run.nOptions.Concat = FALSE;
  141.         }
  142.  
  143.         if(!fileOutput.Open(run.sOutputFile, nOptions, &e))
  144.         {
  145.             nRet = e.m_cause;
  146.             PrintError(run.sOutputFile, NO_LINE, nRet);
  147.             goto ExitError;
  148.         }
  149.  
  150.         if(run.nOptions.Concat)
  151.         {
  152.             nRet = SeekTail(fileOutput, fmt);
  153.             if(nRet)
  154.             {
  155.                 PrintError(run.sOutputFile, NO_LINE, nRet);
  156.                 goto ExitError;
  157.             }
  158.         }
  159.     }
  160.  
  161.     // Extract comment text
  162.  
  163.     ExtractTopics(fileTemp, run, log, fmt);
  164.  
  165.     // Sort da log.
  166.  
  167.     log.Sort(! run.nOptions.Unsorted);
  168.  
  169.     // Create the final output file
  170.     
  171.     if(!run.nOptions.NoOutput)
  172.     {
  173.         if(run.nOptions.Verbose)
  174.             fprintf(stdout, "Writing topics...\n");
  175.             
  176.         // Sort log. Needs to be sorted to lookup information.
  177.  
  178.         GenerateOutput(log, run, fmt, fileTemp, fileOutput);
  179.  
  180.         // Close output file
  181.         fileOutput.Close();
  182.         
  183.         // Generate HPJ file for WinHelp output
  184.         if(_strcmpi(run.sOutputType, "help") == 0)
  185.         {
  186.             if(run.nOptions.Verbose)
  187.                 fprintf(stdout, "Writing HPJ file...\n");
  188.         
  189.             OutputWinHelpHPJFile(run.sOutputFile, sAutoduckName);
  190.         }
  191.     }
  192.  
  193.     // Close (and delete) temp file
  194.  
  195.     fileTemp.Close();
  196.     remove(run.sTempFile);
  197.  
  198.     // Generate log file - always sort.
  199.  
  200.     if(!run.sLogFileOut.IsEmpty())
  201.     {
  202.         if (run.nOptions.Verbose)
  203.             fprintf(stdout, "Creating log file...\n");
  204.         
  205.         nRet = log.Print(run.sLogFileOut, run.nOptions.Concat);
  206.         if(nRet)
  207.             PrintError(run.sLogFileOut, NO_LINE, nRet);
  208.     }
  209.     
  210. ExitError:
  211.  
  212.     // Free input files list.
  213.         
  214.     for(i = 0, n = run.asInputFiles.GetSize(); i < n; i++)
  215.         delete run.asInputFiles[i];
  216.     for(i = 0, n = run.asFmtFiles.GetSize(); i < n; i++)
  217.         delete run.asFmtFiles[i];
  218.  
  219.     return nRet;
  220. }
  221. CATCH(CFileException, e)
  222. {
  223.     PrintError(NULL, NO_LINE, e->m_cause + 100);
  224.     return e->m_cause;
  225. }
  226. AND_CATCH(CMemoryException, e)
  227. {
  228.     PrintError(NULL, NO_LINE, errMemory);
  229.     return errMemory;
  230. }
  231. END_CATCH
  232. }
  233.  
  234.  
  235. void PrintVersion(const char *szName)
  236. {
  237.     DWORD dwVerSize, dwZero;
  238.     LPSTR lpstrVer;
  239.     UINT  uVerLen;
  240.  
  241.     char szFullPath[_MAX_PATH+1];
  242.  
  243.     GetModuleFileName(NULL, szFullPath, MAX_PATH);
  244.  
  245.     if((dwVerSize = GetFileVersionInfoSize(szFullPath, &dwZero)) == 0)
  246.     {
  247.         return;
  248.     }
  249.  
  250.     void *pVer = new char[dwVerSize];
  251.     if(pVer == NULL)
  252.     {
  253.         return;
  254.     }
  255.  
  256.     if(!GetFileVersionInfo(szFullPath, NULL, dwVerSize, pVer))
  257.     {
  258.         return;
  259.     }
  260.  
  261.     if(!VerQueryValue(pVer, "\\StringFileInfo\\040904E4\\FileVersion", 
  262.             (LPVOID *)&lpstrVer, &uVerLen))
  263.     {
  264.         return;
  265.     }
  266.  
  267.     fprintf(stderr, "%s - Source Documentation Tool ", szName);
  268.     fprintf(stderr, "Version %s\n", lpstrVer);
  269.  
  270.     delete pVer;
  271. }
  272.  
  273. /*
  274. @func Populates the topic log with topic names read from
  275. the textual topic log provided on the command line.
  276.  
  277. @rdesc Zero if success or or an error code.
  278. */
  279.  
  280.  
  281. int PopulateLog(
  282.     CTopicLog &log,             //@parm Log to populate
  283.     const char *szFilename)     //@parm Log filename
  284. {
  285. TRY
  286. {
  287.     if(*szFilename == '\0')
  288.         return 0;
  289.  
  290.     char szInBuf[1024];
  291.     CTopic *pNew;
  292.     int nLen;
  293.  
  294.     CStdioFile fileLog(szFilename, CFile::typeText | CFile::modeRead);
  295.  
  296.     int nRet = 0;
  297.     while(nRet == 0 && fileLog.ReadString(szInBuf, 1024))
  298.     {
  299.         if(*szInBuf && (*szInBuf != '\n'))
  300.         {
  301.             nLen = strlen(szInBuf);
  302.             if(szInBuf[nLen-1] == '\n')
  303.                 szInBuf[nLen-1] = '\0';
  304.             
  305.             pNew = new CTopic;
  306.             pNew->SetContext(szInBuf);
  307.             
  308.             log.Add( pNew, CTopicLog::AddOverwrite );
  309.         }
  310.     }
  311.     fileLog.Close();
  312.  
  313.     return nRet;
  314. }
  315. CATCH(CFileException, e)
  316. {
  317.     return e->m_cause;
  318. }
  319. AND_CATCH(CMemoryException, e)
  320. {
  321.     return errMemory;
  322. }
  323. END_CATCH
  324. }
  325.  
  326.  
  327.  
  328. /*
  329. @func This function generates a filename for a temporary file, in the directory pointed
  330. to by the TEMP environment variable. The filename consists of the letters
  331. AD followed by the process Id of Autoduck. The filename, including directory,
  332. is returned in the buffer pointed to by <p szName>.
  333.  
  334. @parm char *|szName | Buffer in which to print temp filename.
  335. */
  336.  
  337. void GenerateTempFilename(
  338.     CString &sName)
  339. {
  340.     char szName[_MAX_PATH];
  341.     char *szTmpDir = getenv("TEMP");
  342.     int  nPid = _getpid();
  343.  
  344.     if(szTmpDir)
  345.     {
  346.         if(szTmpDir[strlen(szTmpDir)-1] == '\\')
  347.             szTmpDir[strlen(szTmpDir)-1] = '\0';
  348.         sprintf(szName, "%s/~AD%05d.tmp", szTmpDir, nPid);
  349.     }
  350.     else
  351.     {
  352.         sprintf(szName, "~AD%05d.tmp", nPid);
  353.     }
  354.  
  355.     sName = szName;
  356. }
  357.  
  358.  
  359. /*
  360. @func Generates a default output filename using the base filename of the first
  361. input file in the list, and an extension drawn from the [token] section of the
  362. format file.
  363.  
  364. @rdesc Zero if successful or errCantDeduceOutput.
  365. */
  366.  
  367. int GenerateOutputFilename(
  368.     CString &sOutput,               //@parm <c CString> to receive output filename
  369.     const char *szInput1,           //@parm Filename of first input file on list
  370.     const char *szExt)              //@parm Default output extension
  371. {
  372.     char szFileBuf[_MAX_PATH+1];
  373.  
  374. #if defined(_DOS)
  375.     _find_t fileInfo;
  376. #else
  377.     _finddata_t fileInfo;
  378.     long hFile;
  379. #endif
  380.  
  381.     strcpy(szFileBuf, szInput1);
  382.  
  383. #if defined(_DOS)
  384.     if(_dos_findfirst(szFileBuf, _A_NORMAL, &fileInfo))
  385. #else
  386.     if((hFile = _findfirst(szFileBuf, &fileInfo)) == -1L)
  387. #endif
  388.     {
  389.         return errCantDeduceOutput;
  390.     }
  391.  
  392.     // Use name of first specified file
  393.  
  394.     _splitpath(fileInfo.name, NULL, NULL, szFileBuf, NULL);
  395.  
  396.     sOutput =  szFileBuf;
  397.     sOutput += chPeriod;
  398.     sOutput += szExt;
  399.  
  400.     return 0;
  401. }
  402.  
  403. /*
  404. @func Generates the output into the specified output file.
  405. */
  406. void GenerateOutput(
  407.     CTopicLog &log,         //@parm List of topics
  408.     RUNOPTIONS &run,        //@parm Runtime options structure
  409.     FormatInfo &fmt,        //@parm Format informatoin
  410.     CFile &fileTemp,        //@parm Temp fiel containing extracted text
  411.     CAdOutput &fileOutput)  //@parm Output file
  412. {
  413. TRY
  414. {
  415.     int      i;
  416.     int      nRet;
  417.  
  418.     CFmtFile *pfmtFile = (CFmtFile *)fmt.file.Get(NULL);
  419.  
  420.     nRet = fileOutput.SetOutputBuffer(4096);
  421.     if(nRet)
  422.     {
  423.         PrintError(run.sOutputFile, NO_LINE, nRet);
  424.         return;
  425.     }
  426.  
  427.     CCurTopicInfo cur(NULL, fileOutput, fmt, run, log);
  428.  
  429.     if(!run.nOptions.Concat)
  430.         OutputFormatString(cur, pfmtFile, CFmtListFile::tagPre, NULL);
  431.  
  432.     int nTopics = log.GetRealCount();
  433.  
  434.     for(i = 0; i < nTopics; i++)
  435.         OutputTopic(log.GetTopicOutputOrder(i), run, fmt, fileOutput, fileTemp, log);
  436.  
  437.     OutputFormatString(cur, pfmtFile, CFmtListFile::tagPost, NULL);
  438.  
  439.     if(run.nOptions.Verbose)
  440.         fputc(chNewline, stdout);
  441.  
  442.     fileOutput.FlushOutputBuffer();
  443. }
  444. CATCH(CMemoryException, e)
  445. {
  446.     PrintError(NULL, NO_LINE, errMemory);
  447. }
  448. AND_CATCH(CFileException, e)
  449. {
  450.     PrintError(run.sOutputFile, NO_LINE, e->m_cause + 100);
  451. }
  452. END_CATCH
  453. }
  454.  
  455.  
  456.  
  457. /*
  458. @func This function finds the end of the specified RTF file,
  459. and positions the file pointer at the position of the last
  460. closing brace (the RTF EOF).
  461.  
  462. @rdesc Returns 1 if successful or 0 if unsuccessful.
  463.  
  464. @comm This function resets the OPTION_CONCAT flag specified in
  465. <p pnOptions> if the RTF file is zero length.
  466. */
  467.  
  468. int SeekTail(
  469.     CFile &fileOut,       //@parm RTF file to append
  470.     FormatInfo &fmt)
  471. {
  472.     UINT   nRead;
  473.     DWORD  dwChars;
  474.     DWORD  dwPos;
  475.     DWORD  dwSeek;
  476.  
  477.     dwChars = fileOut.GetLength();
  478.     
  479.     if(0 == dwChars)
  480.         return 0;
  481.  
  482.     dwPos = fileOut.Seek(0, CFile::end);
  483.  
  484.     // See if file format info in format file - we will get
  485.     // the file footer information and try to find the footer.
  486.  
  487.     CFmtFile *pfmtFile = (CFmtFile *)fmt.file.Get(NULL);
  488.     if(NULL == pfmtFile)
  489.         return 0;
  490.  
  491.     CString &sFmt = pfmtFile->GetFmtString(CFmtListFile::tagPost);
  492.     if(sFmt.IsEmpty())
  493.         return 0;
  494.  
  495.     // Figure out how far back to start.
  496.     
  497.     dwSeek = sFmt.GetLength() + 80;
  498.     
  499.     if(dwSeek > dwChars)
  500.         dwSeek = dwChars;
  501.  
  502.     fileOut.Seek(dwSeek * -1, CFile::end);
  503.  
  504.     // Read a chunk of text and find the last occurrence of
  505.     // the closing string in the file.
  506.     
  507.     CString sBuf;
  508.     char *szBuf = sBuf.GetBufferSetLength(dwSeek+1);
  509.     
  510.     nRead = fileOut.Read(szBuf, dwSeek);
  511.     szBuf[nRead] = '\0';
  512.  
  513.     const char *szNext = szBuf;
  514.     const char *szCur = NULL;
  515.  
  516.     while(szNext = strstr(szNext, sFmt))
  517.     {
  518.         szCur = szNext;
  519.         szNext++;
  520.     }
  521.  
  522.     sBuf.ReleaseBuffer();
  523.  
  524.     // Figure out if we found the end of the file, and
  525.     // seek to that position.
  526.     
  527.     if(NULL == szCur)
  528.         return errCantAppend;
  529.  
  530.     fileOut.Seek(-1 * (nRead - (szCur - szBuf)), CFile::end);
  531.  
  532.     fileOut.Flush();
  533.  
  534.     return 0;
  535. }
  536.  
  537.